package com.yeskery.nut.application.bio;

import com.yeskery.nut.application.NutApplication;
import com.yeskery.nut.application.NutServerConfigure;
import com.yeskery.nut.application.SecureServerContext;
import com.yeskery.nut.core.*;
import com.yeskery.nut.http.bio.BioRequest;
import com.yeskery.nut.http.bio.BioResponse;

import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * BIO 方式下的 Nut Server 类
 * 如果需要实现其它类型的证书，可以实现 {@link SecureServerContext}
 * 接口，并以 {@link #BioSecureNutServer(SecureServerContext)} 构造
 * 方法创建 Nut Server 类。<b>该类仅用于测试</b>
 *
 * @author sprout
 * 2019-03-21 11:15
 * @version 1.0
 *
 * @see com.yeskery.nut.application.NutServer
 * @see com.yeskery.nut.application.bio.BioNutServer
 * @see SecureServerContext
 *
 * @deprecated 推荐使用 {@link com.yeskery.nut.application.sun.SunSecureNutServer}
 * 、 {@link com.yeskery.nut.application.jetty.JettyNutServer}、{@link com.yeskery.nut.application.netty.NettyNutServer}。
 */
@Deprecated
public class BioSecureNutServer extends BioNutServer {

	/** 日志对象 */
	private static final Logger logger = Logger.getLogger(BioSecureNutServer.class.getName());

	/** SecureServerContext 对象 */
	private final SecureServerContext secureServerContext;

	/**
	 * 以自定义形式的证书构造安全的 Nut Server 类
	 * @param secureServerContext 安全的上下文容器
	 */
	public BioSecureNutServer(SecureServerContext secureServerContext) {
		if (secureServerContext == null) {
			throw new NutException("SecureServerContext Interface Must Not Be Null.");
		}
		this.secureServerContext = secureServerContext;
	}

	@Override
	public void startServer(NutServerConfigure nutServerConfigure) throws Exception {
		// 创建服务器的 socket factory
		SSLServerSocketFactory sslServerSocketFactory = secureServerContext.getSslContext().getServerSocketFactory();

		// 创建一个服务器Socket
		SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(nutServerConfigure.getPort());
		sslServerSocket.setNeedClientAuth(false);
		serverSocket = sslServerSocket;
		logger.info(getServerStartedTip(nutServerConfigure.getPort(), "BIO", true));
		doStartServer(nutServerConfigure.getNutApplication(), nutServerConfigure.getServerContext(),
				nutServerConfigure.getDispatcher(), nutServerConfigure.getSessionManager(), nutServerConfigure.getServerRequestConfiguration());
	}

	/**
	 * 启动服务
	 * @param nutApplication Nut应用对象
	 * @param serverContext 服务上下文
	 * @param dispatcher 请求转发器
	 * @param sessionManager session 管理器
	 * @param serverRequestConfiguration 服务请求配置对象
	 * @throws IOException IOException
	 */
	@Override
	void doStartServer(NutApplication nutApplication, ServerContext serverContext, Dispatcher dispatcher,
					   SessionManager sessionManager, ServerRequestConfiguration serverRequestConfiguration) throws IOException {
		while (!serverSocket.isClosed()) {
			SSLSocket socket = null;
			InputStream inputStream = null;
			OutputStream outputStream = null;
			try {
				socket = (SSLSocket) serverSocket.accept();
				socket.setEnabledCipherSuites(socket.getSupportedCipherSuites());
				// Start handshake
				socket.startHandshake();

				inputStream = socket.getInputStream();
				outputStream = socket.getOutputStream();
				Request request = new BioRequest(socket, serverContext, sessionManager, serverRequestConfiguration);
				Response response = new BioResponse(nutApplication, outputStream);
				//请求执行的方法
				process(request, response, dispatcher, sessionManager);
			} catch (IOException | NutException e) {
				logger.log(Level.WARNING, "An Error Occurred While Deal Request.", e);
			} finally {
				if (outputStream != null) {
					outputStream.close();
				}
				if (inputStream != null) {
					inputStream.close();
				}
				if (socket != null && !socket.isClosed()) {
					socket.close();
				}
			}
		}
	}
}
